using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.IO;
using Oarw.General.Text;
using Oarw.General;
using System.Text.RegularExpressions;

namespace ScreenMonkey.Plugin.Clips.Song
{
    public partial class SongLyricsDialog : Form
    {
        private LyricsSearch search = null;

        public SongLyricsDialog()
        {
            InitializeComponent();

            saveSongDialog.InitialDirectory = SongClipProducer.SongFolder;
            openSongDialog.InitialDirectory = SongClipProducer.SongFolder;


            LoadFilters();
            SongLabels.LabelAdded += SongLabels_LabelAdded;
        }

        private bool EnsureSaved()
        {
            //Prompt the user to save any changes to the song back to the file.
            if (songEdit.Modified && Lyrics != null && File.Exists(Lyrics.FileName))
            {
                DialogResult selection = MessageBox.Show(string.Format("The song \"{0}\" has changes which have not been saved. Do you want to save the changes to this song?", Lyrics.Title == "" ? "Untitled" : Lyrics.Title), "Song Edit", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);

                switch (selection)
                {
                    case DialogResult.Yes:
                        Save(Lyrics.FileName);
                        break;
                    case DialogResult.Cancel:
                        return false;
                }
            }

            return true;
        }

        public void LoadLyrics()
        {


            //Enable the refresh from file prompt.
            refreshSong.Enabled = File.Exists(Lyrics.FileName);

            if (songEdit.Lyrics.Title != "")
                this.Text = songEdit.Lyrics.Title + " - Song Edit";
            else
                this.Text = "Song Edit";
        }

        public void LoadFilters()
        {
            filterSelect.DropDownItems.Clear();

            ToolStripItem newFilter = new ToolStripMenuItem("all");
            newFilter.Font = new Font(newFilter.Font, FontStyle.Bold);
            newFilter.Click += new EventHandler(newFilter_Click);
            filterSelect.DropDownItems.Add(newFilter);

            foreach (string label in SongLabels.Items)
            {
                newFilter = new ToolStripMenuItem(label);
                newFilter.Font = new Font(newFilter.Font, FontStyle.Bold);
                newFilter.Click += new EventHandler(newFilter_Click);
                filterSelect.DropDownItems.Add(newFilter);
            }
        }

        void newFilter_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem item = sender as ToolStripMenuItem;
            if (item != null)
            {
                filterSelect.Text = item.Text;

                if (item.Text == "all")
                {
                    filterSelect.BackColor = Color.Gray;
                    search.SearchLabels.Clear();
                }
                else
                {
                    filterSelect.BackColor = Color.Orange;
                    Search.SearchLabels.Add(item.Text);

                    //Remove any old labels and just have the selected one.
                    foreach (string oldItem in new List<string>(Search.SearchLabels))
                    {
                        if(oldItem != item.Text) Search.SearchLabels.Remove(oldItem);
                    }
                }
            }
        }

        public LyricsSearch Search
        {
            get
            {
                //We create the search here to prevent it unesaserily loading the cache.
                //This way it only loads the cache on first use.
                if (search == null)
                {
                    search = new LyricsSearch();
                    search.DirectoryPath = SongClipProducer.SongFolder;
                    search.StartSearching += new EventHandler(search_StartSearching);
                    search.FinishedSearching += new EventHandler(search_FinishedSearching);
                    search.NewResult += new EventHandler<SearchResultArgs>(search_NewResult);
                }
                return search;
            }
        }

        void SongLabels_LabelAdded(object sender, EventArgs e)
        {
            BeginInvoke(new VoidHandler(LoadFilters));
        }

        private SongDisplayStyle displayStyle = new SongDisplayStyle();

        public SongDisplayStyle DisplayStyle
        {
            get { return displayStyle; }
            set
            {
                displayStyle = value;
            }
        }

        public SongLyrics Lyrics
        {
            get {
                return songEdit.Lyrics; 
            }
            set {
                if (EnsureSaved())
                {
                    songEdit.Lyrics = value;
                    LoadLyrics();
                }
            }
        }

        private SongClip clip= null;

        public SongClip Clip
        {
            get { return clip; }
            set { clip = value; }
        }
	

        private void OKBut_Click(object sender, EventArgs e)
        {          
            //Prompt the user to save any changes to the song.
            if (EnsureSaved())
            {
                if (clip != null) clip.Lyrics = Lyrics;

                DialogResult = DialogResult.OK;
                BeginInvoke(new VoidHandler(Close));
            }
        }

        private void CancelBut_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.Cancel;
            BeginInvoke(new VoidHandler(Close));
        }

        private void saveMnu_Click(object sender, EventArgs e)
        {
            if (File.Exists(songEdit.Lyrics.FileName))
                Save(songEdit.Lyrics.FileName);
            else
                SaveNew();
        }

        private void Save(string filename)
        {
            XmlTextWriter xmlFile;

            xmlFile = new XmlTextWriter(filename, null);
            xmlFile.Formatting = Formatting.Indented;
            xmlFile.WriteStartDocument();

            songEdit.Lyrics.Save(xmlFile);
            songEdit.Lyrics.FileName = filename;

            xmlFile.WriteEndDocument();
            xmlFile.Close();

            refreshSong.Enabled = File.Exists(Lyrics.FileName);

            //Mark the song as unmodified after the save.
            songEdit.Modified = false;
        }

        private void SaveNew()
        {
            string fileNameCleanerExpression = "[" + string.Join("", Array.ConvertAll(Path.GetInvalidFileNameChars(), x => Regex.Escape(x.ToString()))) + "]";
            Regex fileNameCleaner = new Regex(fileNameCleanerExpression, RegexOptions.Compiled);

            saveSongDialog.FileName = fileNameCleaner.Replace(songEdit.Lyrics.Title, "");
            if(saveSongDialog.ShowDialog()== DialogResult.OK)
            {
                Save(saveSongDialog.FileName);
            }
        }

        private void openMenu_Click(object sender, EventArgs e)
        {
            SongLyrics newSong = new SongLyrics();
            XmlDocument songFile;

            if(openSongDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    songFile = new XmlDocument();
                    songFile.Load(openSongDialog.FileName);
                    newSong.Load(songFile.SelectSingleNode("Song"));
                }
                catch (LoadLyricsException ex)
                {
                    MessageBox.Show(ex.Message,"Load Song", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                

                Lyrics = newSong;
            }
        }

        private void newMnu_Click(object sender, EventArgs e)
        {
            Lyrics = new SongLyrics();
        }

        void search_FinishedSearching(object sender, EventArgs e)
        {
            if (InvokeRequired)
            {
                Invoke(new EventHandler(search_FinishedSearching), sender, e);
                return;
            }

            searchProgress.Visible = false;
        }

        void search_StartSearching(object sender, EventArgs e)
        {
            if (InvokeRequired)
            {
                Invoke(new EventHandler(search_StartSearching), sender, e);
                return;
            }

            searchResultsList.Items.Clear();
            searchProgress.Visible = true;

            searchPanel.Visible = true;
        }

        void search_NewResult(object sender, SearchResultArgs e)
        {
            if (InvokeRequired)
            {
                try
                {
                    if(!IsDisposed) Invoke(new EventHandler<SearchResultArgs>(search_NewResult), sender, e);
                }
                catch (ObjectDisposedException)
                {
                    //Difficult to stop this happening.
                }
                
                return;
            }

            searchResultsList.Items.Add(e.Lyrics);
        }

        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DisplayStyleDialog styleDlg = new DisplayStyleDialog();
            styleDlg.TemplateManager = SongClipProducer.TemplateManager;

            styleDlg.DisplayStyle = DisplayStyle;
            if(styleDlg.ShowDialog() == DialogResult.OK)
            {
                DisplayStyle.Copy(styleDlg.DisplayStyle);
            }
        }


        private void searchText_TextChanged(object sender, EventArgs e)
        {
            if(Search.DirectoryPath == "")
            {
                if (MessageBox.Show("To use the search function you must first specify a folder to search. This is a folder which contains song files compatible with Screen Monkey. Once you have specified a folder you will then be able to search through all the files in that folder for specific phrases. as you type the results will be shown in a box bellow, click on the result to display the song.\n\nDo you want to set the search folder?", "Song Search", MessageBoxButtons.OKCancel, MessageBoxIcon.Information) == DialogResult.OK)
                {
                    SelectSearchFolder();
                }
            }
            else
                Search.Search(searchText.Text);
        }

        private void searchFolderBut_Click(object sender, EventArgs e)
        {
            SelectSearchFolder();
        }

        private void SelectSearchFolder()
        {
            searchFolderDialog.SelectedPath = Search.DirectoryPath;
            searchFolderDialog.ShowNewFolderButton = false;
            searchFolderDialog.Description = "Please select a folder which contains song files you wish to search through. The song files should be in the form of an xml file. The search will look for all text within the lyrics of the song.";

            if (searchFolderDialog.ShowDialog() == DialogResult.OK)
            {
                Search.DirectoryPath = searchFolderDialog.SelectedPath;
                SongClipProducer.SongFolder = Search.DirectoryPath;
            }
        }

        private void searchResultsList_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (searchResultsList.SelectedItem is SongLyrics)
            {
                Lyrics = (SongLyrics) searchResultsList.SelectedItem;
            }
        }

        private void searchCollapse_Click(object sender, EventArgs e)
        {
            searchPanel.Visible = false;
        }

        private void saveAsMnu_Click(object sender, EventArgs e)
        {
            SaveNew();
        }

        private void licenseMenuItem_Click(object sender, EventArgs e)
        {
            LicenseTextDialog license = new LicenseTextDialog();
            license.LicenseText = SongLyrics.License;

            if (license.ShowDialog(this) == DialogResult.OK)
            {
                SongLyrics.License = license.LicenseText;
            }
        }

        private void applyButton_Click(object sender, EventArgs e)
        {
            if (clip != null) clip.Lyrics = Lyrics;
        }

        private void refreshSong_Click(object sender, EventArgs e)
        {
            if(File.Exists(songEdit.Lyrics.FileName))
            {
                Lyrics = new SongLyrics(songEdit.Lyrics.FileName);
            }
        }

        private void editSongTags_Click(object sender, EventArgs e)
        {
            SongTagsEditor edit = new SongTagsEditor();

            edit.ShowDialog();
        }

        private void SongLyricsDialog_Load(object sender, EventArgs e)
        {
            //Focus the search box.
            searchText.Focus();
        }

        private void searchText_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Down)
            {
                if (searchResultsList.Items.Count > 0)
                {
                    if (searchResultsList.SelectedIndex == searchResultsList.Items.Count - 1)
                    {
                        searchResultsList.SelectedIndex = 0;
                    }
                    else 
                    {
                        searchResultsList.SelectedIndex++; 
                    }
                }
                return;
            }
            if (e.KeyCode == Keys.Up)
            {
                if (searchResultsList.Items.Count > 0)
                {
                    if (searchResultsList.SelectedIndex == 0)
                    {
                        searchResultsList.SelectedIndex = searchResultsList.Items.Count - 1;
                    }
                    else
                    {
                        searchResultsList.SelectedIndex--;
                    }
                }
                return;
            }
            if (e.KeyCode == Keys.Return)
            {
                if (searchResultsList.Items.Count > 0 && searchResultsList.SelectedItem != null)
                {
                    OKBut_Click(sender, e);
                    return;
                }
            }
        }
    }
}